﻿
#ifndef _LST_LOG_20220128_H_
#define _LST_LOG_20220128_H_
#include <sstream>
#ifdef WIN32
//#include <sys/timeb.h>
#include <time.h>
#else
#include <sys/time.h>
#endif

#include "SLT_tool_pub_def.h"

static void SLT_AscToHex2(const char* strasc, int asclen, std::string& _out)
{
	char buf[16];
	for (int i = 0; i < asclen; ++i)
	{
		if (i % 16 == 0) {
			_out += "_";
		}if (i % 2 == 0) {
			_out += " ";
		}
		snprintf(buf, sizeof(buf), "%02X", (unsigned char)strasc[i]);
		_out += buf;
	}
}
static std::string SLT_AscToHex2(const char* strasc, int asclen)
{
	std::string str;
	SLT_AscToHex2(strasc, asclen, str);
	return str;
}
#if 0
std::string dump_memory(const char* pBuf, size_t iLen, const char* pTitle, bool bAddrDisplay, bool bHexSpin, bool bAscDisplay, int width)
{
	width = std::max( (width&0xFFF8), 0x8);	// width为8的倍数，最小8

	#define ASCII_SPACE "  "
	unsigned char* pTmp = (unsigned char*)pBuf;
	bool bAscTail = false;	// 表示ASCII还有未输出的部分
	int iColumn = 0;
	char szTmp[32];
	std::string szAll(pTitle==NULL?"":pTitle), szAscii=ASCII_SPACE;

	szAll.append("\n");

	size_t line_posi = 0;

	for (size_t i=0; i<iLen; ++i,++pTmp)
	{
		bAscTail = bAscDisplay ? true : false;

		iColumn = i % width + 1; // 0x10;	// [1, width]

		// 行头
		if ( (1 == iColumn) && bAddrDisplay)
		{
			if (bAddrDisplay)
			{
				sprintf(szTmp, "%04X    ", (int)i);
				szAll.append(szTmp);
			}

			line_posi = szAll.size();
		}

		// 输出HEX数据
		sprintf(szTmp, "%02X ", *pTmp);
		szAll.append(szTmp);

		if (bAscDisplay)
		{
			szAscii.push_back(isprint(*pTmp) ? (*pTmp) : '.');
		}
	
		// 行中
		if ( (0 == iColumn%8) && bHexSpin)
		{
			szAll.push_back(' ');
			szAscii.push_back(' ');
		}

		// 行尾
		if (width == iColumn)
		{
			if (bAscDisplay)
			{
				szAll += szAscii;
				szAscii = ASCII_SPACE;	//.clear();
				bAscTail = false;
			}

			szAll.push_back('\n');
		}
	}

	// hex dump完成了，看是否还有未输出的ASC部分
	if (bAscTail)
	{
		// 需要先补足HEX部分的空格, 少一个数字就是3个空格，如果iColumn小于7，再加2个分割用的空格
		int line_size = width*3 + (bHexSpin?(width/8):0);	// 一行的最大值
		int iSpace = line_size - (szAll.size()- line_posi);	// 减去已经写入的值
		szAll.insert(szAll.end(), iSpace, ' ');
		szAll += szAscii;
	}

	// 最后，输出信息
	return szAll;
}
#endif


////////////////////////////////////////////////////////////////////////////////////////////////////////////////
enum SLT_LOG_LEVEL
{
	SLT_TRACE,
	SLT_DEBUG,
	SLT_INFO,
	SLT_WARM,
	SLT_ERROR,
	SLT_FATAL,
	SLT_MAX,
	SLT_UNKNOW
};

//日志配置文件，默认进程当前目录,必须在SLT_logInit之前调用
SLT_API void	SLT_setLogConfig(const char* _configFile);
//是否打开定时扫描配置文件 默认打开 true:打开，false:关闭   
SLT_API void  SLT_enableConfig(bool _bconfig);
//设置日志输出目录，默认进程当前目录log下,,必须在SLT_logInit之前调用
SLT_API void    SLT_setLogPath(const char* _logpath);		 
//设置日志打印级别 _id：对应模块 _level：等级 [0:TRACE,1:DEBUG,2:INFO,3:WARM,4:ERROR,5:FATAL,6:MAX]
SLT_API void    SLT_setLogLevel(int _id,int _level);
//设置日志是否输出屏幕 _id：对应模块 _disp：0：不打印输出 1：异步打印输出
SLT_API void    SLT_setLogDisplay(int _id, int _disp);
//设置日志是否输出屏幕 _id：对应模块 _sync：0：不同步打印输出 1：同步打印输出
SLT_API void    SLT_setLogDisplaySync(int _id, int _sync);

//进程只调用一次。创建日志输出目录，默认进程当前目录log下
//日志模块建议进程启动初始化一次，进程结束调用反初始化接口一次（也可以不调用)
SLT_API int		SLT_logInit();
SLT_API void	SLT_logUninit();

SLT_API void	SLT_WriteLog(int _id,int _level, const char *_pfile,int _fileline,const char* _mesg, ...);  //输出日志
SLT_API bool	SLT_checkLogShow(int _id, int _level);  //检查日志级别是否显示


#if 0
#ifdef WIN32
#define SLT_LOG(_id,_level,_format,...) \
	if(SLT_checkLogShow(_id,_level)) {SLT_WriteLog(_id,_level,__FILE__,__LINE__,_format "\n",##__VA_ARGS__);}
#else
#define SLT_LOG(_id,_level,_format,...) \
	if(SLT_checkLogShow(_id,_level)) {SLT_WriteLog(_id,_level,__FILE__,__LINE__,_format "\n",##__VA_ARGS__);}
#endif
#endif

#define SLT_LOG(_id,_level,_format,...) \
	if (SLT_checkLogShow(_id, _level)) { SLT_WriteLog(_id, _level, __FILE__, __LINE__, _format "\n", ##__VA_ARGS__); }

#define  SLT_LOG_TRACE(_format,...) SLT_LOG(0,SLT_TRACE,_format, ##__VA_ARGS__)
#define  SLT_LOG_DEBUG(_format,...) SLT_LOG(0,SLT_DEBUG,_format, ##__VA_ARGS__)
#define  SLT_LOG_INFO(_format,...) SLT_LOG(0,SLT_INFO,_format, ##__VA_ARGS__)
#define  SLT_LOG_WARM(_format,...) SLT_LOG(0,SLT_WARM,_format, ##__VA_ARGS__)
#define  SLT_LOG_ERR(_format,...) SLT_LOG(0,SLT_ERROR,_format, ##__VA_ARGS__)


class SLT_logwriter 
{
public:
	SLT_logwriter(int _mid,int _level,const char *_pfile,int _fileline) 
	{
		m_mid = _mid; m_level = _level; m_pfile = (char*)_pfile; m_fileline = _fileline;
	}
	~SLT_logwriter() {
		//
		SLT_WriteLog(m_mid, m_level, m_pfile, m_fileline,"%s\n", m_stream.str().c_str());
	}

	template <typename T>
	inline SLT_logwriter& operator<<(const T& _log) {
		m_stream << _log;
		return *this;
	}

	std::stringstream  m_stream;
	int m_mid;
	int m_level;
	char* m_pfile;
	int m_fileline;
};

#define  SLT_LOGS_DEBUG() SLT_logwriter(0,SLT_DEBUG,__FILE__,__LINE__)
//#define  LOG(_level) SLT_logwriter(0,_level,__FILE__,__LINE__)
#endif // !_PUBLICFUNC_H_

